//! \file UI.c
//! \brief TODO: Document
// -----------------------------------------------------------------------------
//! This program is free software; you can redistribute it and/or
//! modify it under the terms of the GNU General Public License
//! as published by the Free Software Foundation; either version 2
//! of the License, or (at your option) any later version.
//!
//! This program is distributed in the hope that it will be useful,
//! but WITHOUT ANY WARRANTY; without even the implied warranty of
//! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//! GNU General Public License for more details.
//!
//! You should have received a copy of the GNU General Public License
//! along with this program; if not, write to the Free Software Foundation,
//! Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
// -----------------------------------------------------------------------------

#include "UI.h"
#include "Gui.h"

//#include "UiConsole.h"
#include "Core.h"

//#include "DataBase.h" TODO: ??
#include "DataBase.h"
#include "DataTypes.h"

#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <CEGUI.h>
//#include <RendererModules/OpenGL/CEGUIOpenGL.h>
#include <CEGUI/RendererModules/OpenGL/CEGUIOpenGLRenderer.h>
#include <CEGUIDefaultResourceProvider.h>

//#include "Sample_FirstWindow.h"

using namespace CEGUI;


//#include <string.h>
//#include <stdio.h>
//#include <stdlib.h>

//#include <agar/core.h>
//#include <agar/gui.h>

//#include "UiWindowMain.h"

// =====[ Local Definitions ]===================================================

// =====[ Local DataTypes ]=====================================================

// =====[ Local Variables ]=====================================================
//static int Count = 0;
static SDL_Surface* pSurface;
static SDL_Surface* pImage;
//static AG_Surface* pScreen;
//static AG_Surface* pMyImage;

//AG_Pixmap *pPixmap;
bool must_quit = false;
double last_time_pulse = 0.001*static_cast<double>(SDL_GetTicks());

//static AG_Textbox *textbox;

// =====[ Local Functions ]=====================================================
//static void _UI_Exit(void);
//static void _UI_Test(void);
//static void _UI_DoSomething(void);
//static tERROR _UI_Fault(tERROR Error);

void inject_input(bool& must_quit);
void inject_time_pulse(double& last_time_pulse);
void render_gui();
void handle_mouse_down(Uint8 button);
void handle_mouse_up(Uint8 button);



static tERROR _UI_InitWindow(void);

// =====[ Local Implementation ]================================================


// =============================================================================
// Implement: X
// -----------------------------------------------------------------------------
void* UI_Task(void* Args)
{
//  tERROR Error;

  #if dDEBUG_ENABLE
    puts("[START] UI_Task");
  #endif

//  // TODO: comment and check error.
//  Error = _UI_Initialize();
//  Error = _UI_InitResourceProvider();
//
//
//  // create (load) the TaharezLook scheme file
//  // (this auto-loads the TaharezLook looknfeel and imageset files)
//  CEGUI::SchemeManager::getSingleton().create( "TaharezLook.scheme" );
//
//  // create (load) a font.
//  // The first font loaded automatically becomes the default font, but note
//  // that the scheme might have already loaded a font, so there may already
//  // be a default set - if we want the "Commonweath-10" font to definitely
//  // be the default, we should set the default explicitly afterwards.
//  CEGUI::FontManager::getSingleton().create( "DejaVuSans-10.font" );
//
//
//  //System::getSingleton().setDefaultFont( "DejaVuSans-10" );
//  System::getSingleton().setDefaultMouseCursor( "TaharezLook", "MouseArrow" );
////  System::getSingleton().setDefaultToolTip( "TaharezLook/Tooltip" );

    Gui::Start();

  _UI_InitWindow();

  UI_Start();

  #if dDEBUG_ENABLE
    puts("[STOP] UI_Task");
  #endif

    return (0);
}

// =============================================================================
// Implement: UI_Start
// -----------------------------------------------------------------------------
tERROR UI_Start(void)
{/*
  // Initialize SDL.
  if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
    { return (UI_Stop(dERROR_UI_DISPLAY_FAILED_TO_START)); }

  // Create our drawing surface.
//  pSurface = SDL_SetVideoMode(800, 600, 16, SDL_SWSURFACE);
  pSurface = SDL_SetVideoMode(800, 600, 0, SDL_OPENGL);
  if (pSurface == NULL) return (UI_Stop(dERROR_SDL_SURFACE_CREATION));

//  FirstWindowSample app;
//  return app.run();

  // TODO: comment CEGUI config stuff...
  glEnable(GL_CULL_FACE);
  glDisable(GL_FOG);
  glClearColor(0.0f,0.0f,0.0f,1.0f);
  glViewport(0,0, 800,600);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45.0, 800.0/600.0, 0.1,100.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();


  CEGUI::OpenGLRenderer::bootstrapSystem();

  SDL_ShowCursor(SDL_DISABLE);

  SDL_EnableUNICODE(1);

  SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
*/
//  CEGUI::OpenGLRenderer* renderer = new CEGUI::OpenGLRenderer(0,800,600);

//  Blah();

  while (!must_quit)
  {
    inject_input(must_quit);
    inject_time_pulse(last_time_pulse);
    render_gui();
  }


  // Create our image.
  pImage = SDL_LoadBMP("hello.bmp");
  if (pImage == NULL) return (UI_Stop(dERROR_SDL_IMAGE_CREATION));

//  // Create and start our UI display thread.
//  pThread = SDL_CreateThread(&_UI_DisplayTask, NULL);
//  if (pThread == NULL) return (UI_Stop(dERROR_SDL_THREAD_CREATION));

  // Finally, return success.
  return (0);












/*
//  AG_Window *pWin;
//  AG_Pane *pPaneH, *pPaneV;
//  AG_Console *pConsole;

//  char *driverSpec = NULL, *optArg;
//  char *driverSpec = "<OpenGL>(width=640:height=480:depth=32)";
//  char *driverSpec = "(width=640:height=480:depth=32)";


//  if (AG_InitVideo(1024, 768, 32, (AG_VIDEO_SDL | AG_VIDEO_RESIZABLE)) == -1)
//    { return (UI_Stop(dERROR_UI_DISPLAY_FAILED_TO_START)); }

//  if (AG_InitGraphics(NULL) == -1)
//    { return (UI_Stop(dERROR_UI_DISPLAY_FAILED_TO_START)); }

  AG_ColorsLoad("dungeonquest.acs");*/

//  // Initialize SDL.
//  if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
//    { return (UI_Stop(dERROR_UI_DISPLAY_FAILED_TO_START)); }

//  #define AG_VIDEO_HWSURFACE     0x0001  /* Request hardware FB */
//  #define AG_VIDEO_ASYNCBLIT     0x0002  /* Multithreaded blits */
//  #define AG_VIDEO_ANYFORMAT     0x0004  /* Disable depth emulation */
//  #define AG_VIDEO_HWPALETTE     0x0008  /* Exclusive palette access */
//  #define AG_VIDEO_DOUBLEBUF     0x0010  /* Double buffering */
//  #define AG_VIDEO_FULLSCREEN    0x0020  /* Start in fullscreen mode */
//  #define AG_VIDEO_RESIZABLE     0x0040  /* Request resizable window */
//  #define AG_VIDEO_NOFRAME       0x0080  /* Request frameless window */
//  #define AG_VIDEO_BGPOPUPMENU   0x0100  /* Set a background popup menu */
//  #define AG_VIDEO_OPENGL        0x0200  /* Require OpenGL mode */
//  #define AG_VIDEO_OPENGL_OR_SDL 0x0400  /* Prefer OpenGL mode */
//  #define AG_VIDEO_NOBGCLEAR     0x0800  /* Don't clear background on init */
//  #define AG_VIDEO_OVERLAY       0x1000  /* Overlay in OpenGL mode */
//  #define AG_VIDEO_SDL           0x2000  /* Prefer SDL mode */


/*  // Create our drawing surface.
  pSurface = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE);
  if (pSurface == NULL) { return (UI_Stop(dERROR_SDL_SURFACE_CREATION)); }

//  pScreen = AG_SurfaceFromSDL(pSurface);

//  pSurface = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE);
//  if (pSurface == NULL) return (UI_DisplayStop(dERROR_SDL_SURFACE_CREATION));

  // Create our image.
  pImage = SDL_LoadBMP("hello.bmp");
  if (pImage == NULL) { return (UI_Stop(dERROR_SDL_IMAGE_CREATION)); }*/

//  // Create our image.
//  pMyImage = AG_SurfaceFromBMP("hello.bmp");
//  if (pMyImage == NULL) { return (UI_Stop(dERROR_SDL_IMAGE_CREATION)); }


/*  // Initialize Agar-GUI to reuse display.
  if (AG_InitVideoSDL(pSurface, 0) == -1)
    { return (UI_Stop(dERROR_SDL_IMAGE_CREATION)); }*/


//  pImage = SDL_LoadBMP("hello.bmp");
//  if (pImage == NULL) return (UI_DisplayStop(dERROR_SDL_IMAGE_CREATION));

//  if (SDL_Init(SDL_INIT_EVERYTHING) < 0) Error = dERROR_SDL_START_FAILED;
//  if (Error != ERR_NONE) return (_Main_Shutdown(Error));

//  if (AG_InitCore("agar-console-demo", 0) == -1 || AG_InitGraphics(driverSpec) == -1)

//  if (AG_InitCore("Dungeon Quest", 0) == -1 || AG_InitVideo(640, 480, 32, AG_VIDEO_RESIZABLE) == -1)
////  return (1);
//  {
//    fprintf(stderr, "%s\n", AG_GetError());
//    return (1);
//  }


/*  //AG_BindGlobalKey(AG_KEY_ESCAPE, AG_KEYMOD_ANY, &(_UI_Exit));
  AG_BindGlobalKey(AG_KEY_ESCAPE, AG_KEYMOD_ANY, AG_QuitGUI);
  AG_BindGlobalKey(AG_KEY_F8, AG_KEYMOD_ANY, AG_ViewCapture);
  AG_BindGlobalKey(AG_KEY_A, AG_KEYMOD_ANY, &_UI_Test);*/

/* Console Window
  pWin = AG_WindowNew(AG_WINDOW_PLAIN | AG_WINDOW_KEEPABOVE);
  AG_WindowSetGeometry(pWin, 50, 50, 400, 400);
//  AG_LabelNew(pWin, 0, "Hello, world!");

  pConsole = AG_ConsoleNew(pWin, AG_CONSOLE_EXPAND);

  AG_Box *box;
  AG_Button *btn;

  box = AG_BoxNewHoriz(pWin, AG_BOX_HFILL);

  textbox = AG_TextboxNew(box, AG_TEXTBOX_STATIC|AG_TEXTBOX_HFILL,
      "Input: ");
  AG_SetEvent(textbox, "textbox-return", AppendLine, "%p", pConsole);
  AG_WidgetFocus(textbox);

  btn = AG_ButtonNewFn(box, 0, "OK", AppendLine, "%p", pConsole);
  AG_WidgetSetFocusable(btn, 0);



  box = AG_BoxNewHoriz(pWin, AG_BOX_HFILL|AG_BOX_HOMOGENOUS);
  {
          AG_ButtonNewFn(box, 0, "Junk", AppendLine, "%p", pConsole);
          AG_ButtonNewFn(box, 0, "Clear", AppendLine, "%p", pConsole);
          AG_ButtonNewFn(box, 0, "Sel.Font", AppendLine, "%p", pConsole);
          AG_ButtonNewFlag(box, AG_BUTTON_STICKY, "Debug",
              &pConsole->vBar->flags, AG_SCROLLBAR_TEXT);
  }


  AG_WindowShow(pWin);
*/




  /*  Console window at the bottom of the display.
  // Create the window.
  pWin = AG_WindowNew(AG_WINDOW_PLAIN | AG_WINDOW_KEEPABOVE | AG_WINDOW_NOVRESIZE |
//                      AG_WINDOW_NOMOVE |
                      AG_WINDOW_HMAXIMIZE);
  AG_WindowSetCaption(pWin, "Dungeon Quest"); // Set the window caption.
//  AG_WindowMaximize(pWin);                    // Fill the entire window.
  AG_WindowSetPosition(pWin, AG_WINDOW_BC, 0);
//  AG_WindowSetMinSizePct(pWin, 20);
  AG_WindowSetGeometry(pWin, -1, -1, 640, 100);
  */




/*  // Divide the window vertically.
  pPaneV = AG_PaneNewVert(pWin, AG_PANE_EXPAND);

  // Divide the top pane horizontally.
  pPaneH = AG_PaneNewHoriz(pPaneV->div[0], AG_PANE_EXPAND);
  AG_PaneMoveDividerPct(pPaneH, 20);*/


//  AG_Pane *pPaneH, *pPaneV;



//  /* Divide the window horizontally */
//  paneHoriz = AG_PaneNewHoriz(win, AG_PANE_EXPAND);
//  {
//          /* Divide the left pane vertically */
//          paneVert = AG_PaneNewVert(paneHoriz->div[0], AG_PANE_EXPAND);
//          AG_LabelNew(paneVert->div[0], 0, "Left/Top");
//          AG_LabelNew(paneVert->div[1], 0, "Left/Bottom");
//          AG_PaneMoveDividerPct(paneVert, 30);
//  }
//  AG_LabelNew(paneHoriz->div[1], 0, "Right");
//  AG_PaneMoveDividerPct(paneHoriz, 50);
//  AG_WindowSetGeometry(win, -1, -1, 320, 240);

//  // Adjust the pane dividers as needed.
//  AG_PaneMoveDividerPct(pPaneV, 75);

//  AG_WindowMaximize(pWin);
//  AG_WindowSetGeometry(pWin, -1, -1, 320, 240);

  // Finally, show the window.
//  AG_WindowShow(pWin);


//  AG_SurfaceNew()
//  extern DECLSPEC AG_Surface *AG_SurfaceNew(enum ag_surface_type, Uint, Uint, const AG_PixelFormat *, Uint);

//  AG_Surface * AG_SurfaceNew (enum ag_surface_type type, Uint w, Uint h, const AG_PixelFormat *fmt, Uint flags)

//  pConsole = AG_ConsoleNew(pWin, AG_CONSOLE_EXPAND);

//  UI_ConsoleCreate();
//  UI_OtherCreate();
//  UI_WindowMainNew();

//  AG_EventLoop();

//  _UI_DoSomething();

//  // Update the database that the application is no longer running.
//  DB_SetEnum(eKEY_APPLICATION_IS_RUNNING, 0, eFALSE);

  // TODO: Do thread joins here and wait for the other threads to collapse

  // Stop the user interface.
  UI_Stop(ERR_NONE);

//  puts("UI_Task exiting");

  return (0);
}


// =============================================================================
// Implement: UI_Stop
// -----------------------------------------------------------------------------
tERROR UI_Stop(tERROR Error)
{
//  // Indicate that we are no longer running.
//  IsRunning = eFALSE;

//  // TODO: comment
//  fprintf(stderr, "%s\n", AG_GetError());

//  // Wait for the UI Kill the UI display thread.
//  SDL_WaitThread(pThread, NULL);


  // Free the loaded image.
  if (pImage != NULL) { SDL_FreeSurface(pImage); }

  // Free the drawing surface.
  if (pSurface != NULL) { SDL_FreeSurface(pSurface); }


  // TODO: comment
  SDL_Quit();

  // Log the stop error code.
  Core::LogError(Error);
//  Core_LogError(Error); TODO; remove

  // Finally, return error code.
  return (Error);
}


/*
// =============================================================================
// FxName
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
static void _UI_Exit(void)
{
  // Update the database that the application is no longer running.
  DB_SetEnum(eKEY_APPLICATION_IS_RUNNING, 0, eFALSE);

  // Stop the user interface.
  UI_Stop(ERR_NONE);

//  // Shutdown the Agar GUI.
//  AG_QuitGUI();
//
//  // Destroy the AGAR core.
//  AG_Destroy();
}

static void _UI_Test(void)
{

}


static void _UI_DoSomething(void)
{

}
*/



//static tERROR _UI_Fault(tERROR Error)
//{
//  // TODO: comment
//  fprintf(stderr, "%s\n", AG_GetError());
//
//  // Finally, return the error.
//  return (Error);
//}


void inject_input(bool& must_quit)
{
  SDL_Event e;

  // go through all available events
  while (SDL_PollEvent(&e))
  {
    // we use a switch to determine the event type
    switch (e.type)
    {
      // mouse motion handler
      case SDL_MOUSEMOTION:
        // we inject the mouse position directly.
        CEGUI::System::getSingleton().injectMousePosition(
          static_cast<float>(e.motion.x),
          static_cast<float>(e.motion.y)
        );
        break;

      // mouse down handler
      case SDL_MOUSEBUTTONDOWN:
        // let a special function handle the mouse button down event
        handle_mouse_down(e.button.button);
        break;

      // mouse up handler
      case SDL_MOUSEBUTTONUP:
        // let a special function handle the mouse button up event
        handle_mouse_up(e.button.button);
        break;


      // key down
      case SDL_KEYDOWN:
        // to tell CEGUI that a key was pressed, we inject the scan code.
        CEGUI::System::getSingleton().injectKeyDown(e.key.keysym.scancode);

        // as for the character it's a little more complicated. we'll use for translated unicode value.
        // this is described in more detail below.
        if (e.key.keysym.unicode != 0)
        {
          CEGUI::System::getSingleton().injectChar(e.key.keysym.unicode);
        }
        break;

      // key up
      case SDL_KEYUP:
        // like before we inject the scan code directly.
        CEGUI::System::getSingleton().injectKeyUp(e.key.keysym.scancode);
        break;


      // WM quit event occurred
      case SDL_QUIT:
        must_quit = true;
        break;

    }

  }

}


void inject_time_pulse(double& last_time_pulse)
{
  // get current "run-time" in seconds
  double t = 0.001*SDL_GetTicks();

  // inject the time that passed since the last call
  CEGUI::System::getSingleton().injectTimePulse( float(t-last_time_pulse) );

  // store the new time as the last time
  last_time_pulse = t;
}


void render_gui()
{
  /* clear the colour buffer */
  glClear( GL_COLOR_BUFFER_BIT );

  Gui::DisplayTask(NULL);

  /* render the GUI :) */
  CEGUI::System::getSingleton().renderGUI();

  /* Update the screen */
  SDL_GL_SwapBuffers();
}


void handle_mouse_down(Uint8 button)
{
  switch ( button ) {
    case SDL_BUTTON_LEFT:
      CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::LeftButton);
      break;
    case SDL_BUTTON_MIDDLE:
      CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::MiddleButton);
      break;
    case SDL_BUTTON_RIGHT:
      CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::RightButton);
      break;

    case SDL_BUTTON_WHEELDOWN:
      CEGUI::System::getSingleton().injectMouseWheelChange( -1 );
      break;
    case SDL_BUTTON_WHEELUP:
      CEGUI::System::getSingleton().injectMouseWheelChange( +1 );
      break;
  }
}


void handle_mouse_up(Uint8 button)
{
  switch ( button )
  {
    case SDL_BUTTON_LEFT:
      CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::LeftButton);
      break;
    case SDL_BUTTON_MIDDLE:
      CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::MiddleButton);
      break;
    case SDL_BUTTON_RIGHT:
      CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::RightButton);
      break;
  }
}



// =============================================================================
// FxName
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
static tERROR _UI_InitWindow(void)
{
  using namespace CEGUI;
  WindowManager& wmgr = WindowManager::getSingleton();

//  Window* myRoot = wmgr.createWindow( "DefaultWindow", "root" );
//  System::getSingleton().setGUISheet( myRoot );

  Window* myRoot =  wmgr.getWindow("root");

  FrameWindow* fWnd = static_cast<FrameWindow*>(
  wmgr.createWindow( "TaharezLook/FrameWindow", "testWindow" ));

  myRoot->addChildWindow( fWnd );

  // position a quarter of the way in from the top-left of parent.
  fWnd->setPosition( UVector2( UDim( 0.25f, 0 ), UDim( 0.25f, 0 ) ) );

  // set size to be half the size of the parent
  fWnd->setSize( UVector2( UDim( 0.5f, 0 ), UDim( 0.5f, 0 ) ) );

  fWnd->setText( "Hello World!" );

  return 0; // TODO: fix error code.
}

//
//  // =============================================================================
//  // _UI_DisplayTask
//  // -----------------------------------------------------------------------------
//  //! TODO: document
//  //!
//  //! \param [in] Arg
//  //!   TODO: document
//  //!
//  //! \retval Exception
//  //!   The success status of the requested operation.
//  //!   - eOKAY: Execution occurred as requested.
//  //!   .
//  // -----------------------------------------------------------------------------
//  static int _UI_DisplayTask(void* Data)
//  {
//    SDL_Rect Loc;
//
//    // Initialize the location.
//    Loc.x = 0;
//    Loc.y = 0;
//    Loc.w = 100;
//    Loc.h = 63;
//
//    while (IsRunning == eTRUE)
//    {
//      // ROSO: something.
//      SDL_BlitSurface(pImage, NULL, pSurface, &Loc);
//
//      // Update Screen
//      SDL_Flip(pSurface);
//
//      // Pause
//  //    SDL_Delay(100);
//
//      // Advance the location.
//      if (++(Loc.x) > 640) Loc.x = 0;
//      if (++(Loc.y) > 480) Loc.y = 0;
//    }
//
//    // Finally, return success.
//    return (ERR_NONE);
//  }

